package org.wevil.service.sys;

import org.wevil.entity.cond.CondRoleMenu;
import org.wevil.entity.cond.CondRoleOrg;
import org.wevil.entity.cond.CondRoleSubject;
import org.wevil.entity.cond.CondUserRole;
import org.wevil.entity.sys.SysRole;
import org.wevil.params.add.RoleAP;
import org.wevil.params.delete.DeleteParam;
import org.wevil.params.page.RolePP;
import org.wevil.params.update.RoleMenuUP;
import org.wevil.params.update.RoleOrgUP;
import org.wevil.params.update.RoleUP;
import org.wevil.repo.*;
import org.wevil.repo.sys.SysRoleRepo;
import org.wevil.util.BeanUtil;
import org.wevil.util.page.PageResult;
import org.wevil.util.page.PageResultUtil;
import org.wevil.vo.list.MenuListVo;
import org.wevil.vo.list.OrgListVo;
import org.wevil.vo.list.RoleListVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

/**
 * @author wanglei
 * @since 2021/1/25
 * */
@Service
@Transactional
public class RoleService {

    @Resource
    private CondRoleMenuRepo condRoleMenuRepo;
    @Resource
    private CondUserRoleRepo condUserRoleRepo;
    @Resource
    private CondRoleSubjectRepo condRoleSubjectRepo;
    @Resource
    private CondRoleOrgRepo condRoleOrgRepo;
    @Resource
    private OrgService orgService;
    @Resource
    private SysRoleRepo repo;
    @Resource
    private MenuService menuService;

    /** 用户关联角色 */
    public void userCondRole(Integer userId, Integer roleId){
        condUserRoleRepo.deleteByUserIdAndRoleId(userId, roleId);
        CondUserRole entity = new CondUserRole();
        entity.setUserId(userId);
        entity.setRoleId(roleId);
        condUserRoleRepo.save(entity);
    }

    /** 根据id列表获取角色列表 */
    public List<RoleListVo> getRoleListByIds(List<Integer> roleIds) {
        List<RoleListVo> vos = new ArrayList<>();
        List<SysRole> sysRoles = repo.findByRoleIdIn(roleIds);
        sysRoles.forEach(sysRole -> vos.add(entity2vo(sysRole)));
        return vos;
    }

    /** 获取用户列表 */
    public List<String> gerRoleNamesByIdIn(List<Integer> ids){
        return repo.findRoleNameByRoleIdIn(ids);
    }

    /** 角色分页列表 */
    public PageResult<RoleListVo> page(RolePP param) {
        Integer current = param.getCurrent();
        Integer size = param.getSize();
        // 要查询的字段
        String name = param.getName();
        Specification<SysRole> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (StringUtils.isNotBlank(name)) {
                predicates.add(cb.like(root.get("name").as(String.class), "%" + name + "%"));
            }
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        Sort sort = Sort.by(Sort.Direction.ASC, "name");
        Pageable pageable = PageRequest.of(current - 1, size, sort);
        Page<SysRole> page = repo.findAll(specification, pageable);
        // 封装返回数据
        Iterator<SysRole> iterator = page.iterator();
        List<RoleListVo> voList = new ArrayList<>();
        while (iterator.hasNext()) {
            SysRole next = iterator.next();
            RoleListVo dto = new RoleListVo();
            BeanUtil.copyPropIgnoreNull(next, dto);
            voList.add(dto);
        }
        // 返回
        long total = repo.count(specification);
        return PageResultUtil.generateResult(voList, current, size, total);
    }

    /** 添加角色 */
    public void add(RoleAP param) {
        SysRole entity = new SysRole();
        BeanUtil.copyPropIgnoreNull(param, entity);
        repo.save(entity);
    }

    /** 删除角色 */
    public void del(DeleteParam param) {
        Integer roleId = param.getId();
        Optional<SysRole> optional = repo.findById(roleId);
        if(optional.isPresent()){
            condRoleMenuRepo.deleteByRoleId(roleId);
            condRoleOrgRepo.deleteByRoleId(roleId);
            condUserRoleRepo.deleteByRoleId(roleId);
            repo.deleteById(roleId);
        }
    }

    /**
     * 更新角色
     * */
    public void update(RoleUP param) {
        SysRole entity = new SysRole();
        BeanUtil.copyPropIgnoreNull(param, entity);
        repo.update(entity);
    }

    /**
     * 更新修改菜单
     * */
    public void updateRoleMenu(RoleMenuUP param) {
        Integer roleId = param.getRoleId();
        List<Integer> menuIds = param.getMenuIds();
        condRoleMenuRepo.deleteByRoleId(roleId);
        condRoleMenuRepo.flush();
        if(menuIds != null && menuIds.size()>0){
            menuIds.forEach(menuId -> {
                CondRoleMenu condRoleMenu = new CondRoleMenu();
                condRoleMenu.setRoleId(roleId);
                condRoleMenu.setMenuId(menuId);
                condRoleMenuRepo.save(condRoleMenu);
            });
        }
    }

    /**
     * 更新修改栏目
     * */
    public void updateRoleSubject(Integer roleId, List<Integer> subjectIds) {
        condRoleSubjectRepo.deleteByRoleId(roleId);
        subjectIds.forEach(subjectId -> {
            CondRoleSubject entity = new CondRoleSubject();
            entity.setRoleId(roleId);
            entity.setSubjectId(subjectId);
            condRoleSubjectRepo.save(entity);
        });
    }

    /** 获取角色拥有的菜单Id */
    public List<Integer> getMenuIdsByRoleId(Integer roleId) {
        return condRoleMenuRepo.findMenuIdByRoleId(roleId);
    }

    /** 获取角色拥有的菜单 */
    public List<MenuListVo> getMenu(Integer roleId) {
        List<Integer> menuIds = condRoleMenuRepo.findMenuIdByRoleId(roleId);
        return menuService.getMenuByIds(menuIds);
    }

    /** 获取角色拥有的栏目Id */
    public List<Integer> getSubjectIdsByRoleId(Integer roleId) {
        return condRoleSubjectRepo.findSubjectIdByRoleId(roleId);
    }

    /** 实体转vo */
    private RoleListVo entity2vo(SysRole sysRole) {
        RoleListVo roleListVo = new RoleListVo();
        BeanUtil.copyPropIgnoreNull(sysRole, roleListVo);
        return roleListVo;
    }

    /**
     * 获取用户拥有的角色Id
     * */
    public List<Integer> getRoleIdListByUserId(Integer userId) {
        return condUserRoleRepo.findRoleIdByUserId(userId);
    }

    // ---------------------------------------------组织--------------------------------------------------------//

    /** 获取角色所属组织 */
    public OrgListVo getOrg(Integer roleId) {
        Integer orgId = condRoleOrgRepo.findOrgIdByRoleId(roleId);
        if(orgId != null){
            return orgService.getById(orgId);
        }
        return null;
    }

    /** 修改角色所属组织 */
    public void updateRoleOrg(RoleOrgUP param) {
        Integer roleId = param.getRoleId();
        Integer orgId = param.getOrgId();
        condRoleOrgRepo.deleteByRoleId(roleId);
        condRoleOrgRepo.flush();
        if(orgId != null){
            CondRoleOrg entity = new CondRoleOrg();
            entity.setRoleId(roleId);
            entity.setOrgId(orgId);
            condRoleOrgRepo.save(entity);
        }
    }
}
